﻿namespace SenenFernandez.WindowResizer
{
    using SenenFernandez.SmartExtensionMethods;
    using SenenFernandez.SmartExtensionMethods.Enum;
    using SenenFernandez.SmartExtensionMethods.Interactivity;
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Configuration;
    using System.Linq;
    using System.Runtime.InteropServices;
    using System.Text;
    using System.Text.RegularExpressions;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    using System.Windows.Interop;

    public class MainViewModel : NotificationObject
    {
        private IntPtr mainId;
        private IEnumerable<string> filterList;
        private Display selectedMonitor;
        private IEnumerable<Display> monitors;
        private ICommand dragMove;
        private ICommand loaded;
        private ICommand activated;
        private ICommand resize;
        private ICommand navigate;
        private ICommand closed;

        public Process SelectedWindow { get; set; }

        public IEnumerable<Process> Windows { get; private set; }

        public Display SelectedMonitor { get { return selectedMonitor; } set { SetSelectedMonitor(value); } }

        public IEnumerable<Display> Monitors { get { return monitors; } }

        public int ResizeLeft { get; set; }
        
        public int ResizeTop { get; set; }

        public int ResizeWidth { get; set; }

        public int ResizeHeight { get; set; }

        public ICommand DragMove
        {
            get { return dragMove ?? (dragMove = new DelegateCommand<Window>(OnDragMove)); }
        }

        public ICommand Loaded
        {
            get { return loaded ?? (loaded = new DelegateCommand(OnLoaded)); }
        }

        public ICommand Activated
        {
            get { return activated ?? (activated = new DelegateCommand(OnActivated)); }
        }

        public ICommand Resize
        {
            get { return resize ?? (resize = new DelegateCommand(OnResize)); }
        }

        public ICommand Navigate
        {
            get { return navigate ?? (navigate = new DelegateCommand<string>(OnNavigate)); }
        }

        public ICommand Closed
        {
            get { return closed ?? (closed = new DelegateCommand<Window>(OnClosed)); }
        }

        public MainViewModel()
        {
        }

        private void OnDragMove(Window window)
        {
            if (window != null)
            {
                window.DragMove();
                if (window.WindowState == WindowState.Maximized)
                {
                    window.WindowState = WindowState.Normal;
                }
            }
        }

        private void OnLoaded()
        {
            mainId = new WindowInteropHelper(Application.Current.MainWindow).Handle;
            filterList = ConfigurationManager.AppSettings["filterList"].GetValueOrDefault("Start;Program Manager").ToArray();
            monitors = SmartScreenManager.Monitors;
            RaisePropertyChanged(() => Monitors);
            SetSelectedMonitor(Monitors.FirstOrDefault());
            EventManager.RegisterClassHandler(typeof(TextBox), TextBox.GotFocusEvent, new RoutedEventHandler(OnTextBoxGotFocus));
            EventManager.RegisterClassHandler(typeof(TextBox), TextBox.PreviewMouseDownEvent, new MouseButtonEventHandler(OnTextBoxPreviewMouseDown));
            EventManager.RegisterClassHandler(typeof(TextBox), TextBox.PreviewTextInputEvent, new TextCompositionEventHandler(OnTextBoxPreviewTextInput));
        }

        private void OnActivated()
        {
            var selected = SelectedWindow;
            var windows = new List<Process>();
            User32.EnumDelegate filter = delegate(IntPtr handle, int parameter)
            {
                string name = handle.GetWindowTitle();
                if (handle.IsWindowVisible() && !string.IsNullOrEmpty(name) && !filterList.Contains(name))
                {
                    var id = User32.FindWindow(null, name);
                    if (id != mainId)
                    {
                        windows.Add(new Process(handle, name));
                    }
                }
                return true;
            };
            if (IntPtr.Zero.EnumDesktopWindows(filter, IntPtr.Zero))
            {
                SetValue(() => Windows, windows.OrderBy(source => source.Name));
            }
            if (SelectedWindow == null && windows.Count > 0)
            {
                SetValue(() => SelectedWindow,
                    selected != null
                        ? Windows.FirstOrDefault(source => source.Name.Equals(selected.Name))
                        : Windows.First());
            }
        }

        private void OnResize()
        {
            if (SelectedWindow != null && SelectedWindow.Id != IntPtr.Zero)
            {
                SelectedWindow.Id.RestoreWindow();
                SelectedWindow.Id.MoveWindow(ResizeLeft, ResizeTop, ResizeWidth, ResizeHeight);
                mainId.SetForegroundWindow();
            }
        }

        private void OnNavigate(string link)
        {
            if (!string.IsNullOrEmpty(link))
            {
                System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo(link));
            }
        }

        private void OnClosed(Window window)
        {
            if (window != null)
            {
                window.Close();
            }
        }

        private void OnTextBoxGotFocus(object sender, RoutedEventArgs e)
        {
            var textBox = sender as TextBox;
            if (textBox != null)
            {
                textBox.SelectAll();
            }
        }

        private void OnTextBoxPreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
            var textBox = sender as TextBox;
            if (textBox != null)
            {
                if (!textBox.IsKeyboardFocusWithin)
                {
                    e.Handled = true;
                    textBox.Focus();
                }
            }
        }

        private void OnTextBoxPreviewTextInput(object sender, TextCompositionEventArgs e)
        {
            e.Handled = Regex.IsMatch(e.Text, "[^0-9-]+"); 
        }

        private void SetSelectedMonitor(Display display)
        {
            SetValue(() => SelectedMonitor, ref selectedMonitor, display);
            if (SelectedMonitor != null)
            {
                SetValue(() => ResizeLeft, (int)SelectedMonitor.WorkingArea.Left);
                SetValue(() => ResizeTop, (int)SelectedMonitor.WorkingArea.Top);
                SetValue(() => ResizeWidth, (int)SelectedMonitor.WorkingArea.Width);
                SetValue(() => ResizeHeight, (int)SelectedMonitor.WorkingArea.Height);
            }
        }
    }
}